package cn.ycc1.functionlibrary.streams;

/**
 * Using Optionals
 * @author ycc
 * @date 2025/3/8
 */
public class UsingOptionals {
    /**
     * Supporting Methods That Cannot Produce a Result
     * We already covered several uses of the Optional class, especially in the case where you are calling a terminal operation
     * on a stream that does not have an identity element. This case is not easy to handle because you cannot return any value,
     * including 0, and returning null would make your code have to handle null values in places where you would not want it.
     *
     * Being able to use the Optional class, for the cases where you cannot produce a value, offers many opportunities for better
     * patterns, especially for better handling of errors. This is the main reason why you should be using option objects: they
     * signal that a method may not produce a result in certain circumstances. Storing an instance of Optional instance in
     * a field, in a list, in a map, or passing it as a method argument is not what options have been created.
     *
     * If you design a method that returns an optional, or need to store an optional in a variable, then you should not return
     * null or set this variable to null. You should leverage the fact that your optional can be empty instead.
     *
     * In a nutshell, the Optional class is a wrapper class, that can wrap a reference: Optional<T>, or a value: OptionalInt,
     * OptionalLong, and OptionalDouble. The difference with the classic wrapper types that you already know: Integer, Long,
     * Double, etc... is that an optional object can be empty. Such an instance does not wrap anything.
     *
     * If you need a mechanism to return something from your method that would mean no value and that returning null could lead
     * to errors, including NullPointerException, then you should consider returning an optional object and returning an empty
     * optional in this case.
     */

    /**
     * Creating Optional Objects
     * The Optional class is a final class with private constructor. So, the only way you have to create an instance of it is by
     * calling one of its factory methods. There are three of them.
     *
     * You can create an empty optional by calling Optional.empty().
     * You can wrap a non-null element by calling Optional.of() with this element as an argument. Passing a null reference to
     * this method is not allowed. You will get a NullPointerException in this case.
     * You can wrap any element by calling Optional.ofNullable() with this element as an argument. You may pass a null reference
     * to this method. In this case, you will get an empty optional.
     * These are the only ways to create an instance of this class. As you can see, you cannot wrap a null reference with an
     * optional object. The consequence is that, opening a nonempty optional will always return a non-null reference.
     *
     * The Optional<T> class has three equivalent classes used with the specialized streams of numbers: OptionalInt,
     * OptionalLong, and OptionalDouble. These classes are wrappers of primitive types, that is, values. The method ofNullable()
     * would not make sense for these classes because a value cannot be null.
     */

    /**
     * Opening an Optional Object
     * There are several ways of using an optional and accessing the element it wraps, if any. You can directly query the
     * instance you have and open it if there is something in it, or you can use stream-like methods on it: map(), flatMap(),
     * filter(), and even an equivalent of forEach().
     *
     * Opening an optional to get its content should be made with caution because it will raise a NoSuchElementException if
     * the optional is empty. Unless you are sure that there is an element in your optional, you should protect this operation
     * by first testing it.
     *
     * Two methods are there for you to test your optional object: isPresent(), and isEmpty(), added in Java SE 11.
     *
     * Then, to open your optional, you can use the following methods.
     *
     * get(): this method has been deprecated because is looks like a getter, but it can throw a NoSuchElementException if the
     * optional is empty.
     * orElseThrow() is the preferred pattern since Java SE 10. It does the same as the get() method, but its name does not leave
     * any doubt that it can throw a NoSuchElementException.
     * orElseThrow(Supplier exceptionSupplier): does the same as the previous method. It uses the supplier you pass as an
     * argument to create the exception that it throws.
     * You can also try to get the content of an optional object and provide an object that will be returned in case the optional
     * is empty.
     *
     * orElse(T returnedObject): returns the argument if called on an empty optional.
     * orElseGet(Supplier<T> supplier): does the same as the previous one, without having to build the returned object, in case
     * building this object proves to be expensive. Indeed, the provided supplier is invoked only if needed.
     * Lastly, you can create another optional if this optional is empty.
     *
     * or(Supplier<Optional> supplier): returns this unmodified optional if it is not empty and calls the provided supplier if
     * it is. This supplier creates another optional that is returned by this method.
     */

    /**
     * Processing an Optional Object
     * The Optional class also provides patterns so that you can integrate your optional objects' processing with stream
     * processing. It has methods that directly correspond to methods from the Stream API that you can use to process your
     * data in the same way, and that will seamlessly integrate with streams. Those methods are map(), filter(), and flatMap().
     * They take the same arguments as their twin methods from the Stream API, apart from flatMap(), that takes a function that
     * returns an instance of Optional<T> instead of an instance of Stream.
     *
     * These methods return an optional object with the following convention.
     *
     * If the optional from which they are called is empty, then they return an optional object.
     * If it is not empty, then their argument, function, or predicate is applied to the content of this option. The result is
     * wrapped in another option, which it returned by this method.
     * Using these methods can lead to more readable code in some stream patterns.
     *
     * Suppose you have a list of Customer instances with an id property. You need to find the name of the customer with a given
     * ID. Using the stream vocabulary, you need to find the customer with the given ID, and to map it to its name.
     */

    /**
     * Getting the Two Authors that Published the Most Together
     * Let us examine another, more complex example that demonstrates how to use these methods. Going through this example will
     * show you several of the major patterns of the Stream API, the Collector API, and the optional objects.
     *
     * Suppose you have a set of articles that you need to process. An article has a title, an inception year, and a list of
     * authors. An author has a name.
     *
     * There is a lot of articles in your list, and you need to know what authors have published the largest number of articles
     * together.
     *
     * Your first idea could be to build a stream of pairs of authors for a given article. This is in fact the cartesian product
     * of the set of the authors of a given article. You do not need all the pairs in this stream. You are not interested in
     * the pairs where the two authors are in fact the same author; a pair of two authors (A1, A2) is the same as the pair
     * (A2, A1). To implement this constraint, you can add a constraint to a pair, by stating that, in a pair, the authors
     * are sorted alphabetically.
     */

    /**
     * Getting the Two Authors that Published the Most Together Per Year
     * Let us go one step further and wonder if you could do the same processing for each year. In fact, being able to implement
     * this processing with a single collector would solve your problem because you could then pass it as a downstream collector
     * to a groupingBy(Article::inceptionYear) collector.
     *
     * The postprocessing of the map to extract the maximum can be made a collectingAndThen() collector. This pattern has
     * already been covered in a previous section "Using a Finisher to Post-Process a Collector". This collector is the
     * following.
     */

    /**
     * Avoiding the Opening of Optionals
     * What could be an acceptable pattern in the first context is much more dangerous now. Dealing with it consists of not
     * calling orElseThrow() in the first place.
     *
     * In that case, the collector becomes the following. Instead of creating a key-value pair of pair of authors and a long
     * number, it wraps the result in an optional object.
     */

    /**
     * Consuming the Content of an Optional
     * The Optional class has also two methods that take a consumer as an argument.
     *
     * ifPresent(Consumer consumer): this method calls the provided consumer with the content of this optional, if any. It is
     * in fact equivalent to the Stream.forEach(Consumer) method.
     * ifPresentOrElse(Consumer consumer, Runnable runnable): this method does the same as the previous one if the optional is
     * not empty. If it is, then it calls the provided instance of Runnable.
     */

    /**
     * Stating Some Rules to Use Optionals Properly
     * Rule #1 Never use null for an optional variable or returned value.
     *
     * Rule #2 Never call orElseThrow() or get() unless you are sure the optional is not empty.
     *
     * Rule #3 Prefer alternatives to ifPresent(), orElseThrow(), or get().
     *
     * Rule #4 Do not create an optional to avoid testing for the nullity of a reference.
     *
     * Rule #5 Do not use optional in fields, method parameters, collections, and maps.
     *
     * Rule #6 Do not use identity-sensitive operations on an optional object, such as reference equality, identity hash code,
     * and synchronization.
     *
     * Rule #7 Do not forget that optional objects are not serializable.
     */
}
